/*
 * test_user.c
 *
 * 简单演示如何对 /dev/yourdev0 或 /dev/yourdev1 进行 open/read/write/ioctl/sysfs 操作
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>

#include "your_device.h"  /* 这里需要把内核的 your_device.h 拷贝到 user_test 目录下供编译 */

int main(int argc, char *argv[])
{
    int fd;
    char devname[32];
    ssize_t ret;
    uint32_t data;
    struct yourdev_reg reg;
    int status;

    if (argc != 2) {
        printf("用法: %s <devnum>\n", argv[0]);
        printf("  例如: %s 0   （表示字符设备 /dev/yourdev0）\n", argv[0]);
        return -1;
    }

    snprintf(devname, sizeof(devname), "/dev/yourdev%s", argv[1]);
    fd = open(devname, O_RDWR);
    if (fd < 0) {
        perror("打开设备失败");
        return -1;
    }

    /* 1. read: 从寄存器 0x0 读 4 字节 */
    ret = read(fd, &data, sizeof(data));
    if (ret < 0) {
        perror("read 失败");
    } else {
        printf("read 得到 0x%08x\n", data);
    }

    /* 2. write: 往寄存器 0x0 写 0xA5A5A5A5 */
    data = 0xA5A5A5A5;
    ret = write(fd, &data, sizeof(data));
    if (ret < 0) {
        perror("write 失败");
    } else {
        printf("write 写入 0x%08x\n", data);
    }

    /* 3. ioctl: READ_REG, offset=0x4 */
    reg.offset = 0x4;
    if (ioctl(fd, YOURDEV_IOC_READ_REG, &reg) < 0) {
        perror("ioctl READ_REG 失败");
    } else {
        printf("ioctl READ_REG offset=0x%x 得到 value=0x%x\n", reg.offset, reg.value);
    }

    /* 4. ioctl: WRITE_REG, offset=0x4, value=0xDEADBEEF */
    reg.offset = 0x4;
    reg.value = 0xDEADBEEF;
    if (ioctl(fd, YOURDEV_IOC_WRITE_REG, &reg) < 0) {
        perror("ioctl WRITE_REG 失败");
    } else {
        printf("ioctl WRITE_REG 写入 offset=0x%x value=0x%x\n", reg.offset, reg.value);
    }

    /* 5. ioctl: RESET */
    if (ioctl(fd, YOURDEV_IOC_RESET) < 0) {
        perror("ioctl RESET 失败");
    } else {
        printf("ioctl RESET 执行完毕\n");
    }

    /* 6. ioctl: GET_STATUS */
    if (ioctl(fd, YOURDEV_IOC_GET_STATUS, &status) < 0) {
        perror("ioctl GET_STATUS 失败");
    } else {
        printf("ioctl GET_STATUS 得到 status=%d\n", status);
    }

    /* 7. ioctl: SET_PARAMS */
    {
        struct yourdev_params params;
        params.param1 = 123;
        params.param2 = 456;
        if (ioctl(fd, YOURDEV_IOC_SET_PARAMS, &params) < 0) {
            perror("ioctl SET_PARAMS 失败");
        } else {
            printf("ioctl SET_PARAMS param1=%d param2=%d\n", params.param1, params.param2);
        }
    }

    /* 8. 通过 sysfs 查看和设置参数 */
    {
        char buf[32];
        int val;
        sprintf(devname, "/sys/class/yourdev/yourdev%s/status", argv[1]);
        FILE *fp = fopen(devname, "r");
        if (fp) {
            if (fgets(buf, sizeof(buf), fp)) {
                printf("sysfs status = %s", buf);
            }
            fclose(fp);
        }

        sprintf(devname, "/sys/class/yourdev/yourdev%s/param1", argv[1]);
        fp = fopen(devname, "w");
        if (fp) {
            fprintf(fp, "%d\n", 777);
            fclose(fp);
            printf("sysfs 设置 param1=777\n");
        }

        /* 再读一遍 */
        fp = fopen(devname, "r");
        if (fp) {
            if (fgets(buf, sizeof(buf), fp)) {
                printf("sysfs param1 = %s", buf);
            }
            fclose(fp);
        }
    }

    close(fd);
    return 0;
}
